package com.summo.demo.config.aspect;

import java.util.Objects;

import javax.servlet.http.HttpServletRequest;

import com.alibaba.druid.util.StringUtils;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

@Aspect
@Component
@Slf4j
public class ControllerLoggingAspect {

    /**
     * 拦截所有controller包下的方法
     */
    @Pointcut("execution(* com.summo.demo.controller.*.*(..))")
    private void controllerMethod() {

    }

    @Around("controllerMethod()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        //获取HttpServletRequest
        RequestAttributes ra = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes sra = (ServletRequestAttributes)ra;
        HttpServletRequest request = sra.getRequest();

        // 获取请求相关信息
        String url = request.getRequestURL().toString();
        String method = request.getMethod();
        String uri = request.getRequestURI();
        String params = request.getQueryString();
        if (StringUtils.isEmpty(params) && StringUtils.equals("POST", method)) {
            if (Objects.nonNull(joinPoint.getArgs())) {
                for (Object arg : joinPoint.getArgs()) {
                    params += arg;
                }
            }
        }
        // 获取调用方法相信
        Signature signature = joinPoint.getSignature();
        String className = signature.getDeclaringTypeName();
        String methodName = signature.getName();
        log.info("@http请求开始, {}#{}() URI: {}, method: {}, URL: {}, params: {}",
            className, methodName, uri, method, url, params);
        //result的值就是被拦截方法的返回值
        try {
            //proceed方法是调用实际所拦截的controller中的方法，这里的result为调用方法后的返回值
            Object result = joinPoint.proceed();
            long endTime = System.currentTimeMillis();
            //定义请求结束时的返回数据，包括调用时间、返回值结果等
            log.info("@http请求结束, {}#{}(), URI: {}, method: {}, URL: {}, time: {}ms ",
                className, methodName, uri, method, url, (endTime - startTime));

            return result;
        } catch (Exception e) {
            long endTime = System.currentTimeMillis();
            log.error("@http请求出错, {}#{}(), URI: {}, method: {}, URL: {}, time: {}ms",
                className, methodName, uri, method, url, (endTime - startTime), e);
            throw e;
        }
    }
}

